package com.rc.saas.mini.charge;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.rc.saas.mini.client.ChargerClientRouter;
import com.rc.saas.mini.common.base.TResponse;
import com.rc.saas.mini.common.config.UpYunConfig;
import com.rc.saas.mini.common.constant.HttpConstant;
import com.rc.saas.mini.common.constant.PlatformConstant;
import com.rc.saas.mini.common.constant.WebConstant;
import com.rc.saas.mini.common.utils.DateHelper;
import com.rc.saas.mini.component.RedisLoader;
import com.rc.saas.mini.component.UidGenerator;
import com.rc.saas.mini.evcharge.DataUtil;
import com.rc.saas.mini.evcharge.RedisService;
import com.rc.saas.mini.facede.ElecStationAssemble;
import com.rc.saas.mini.hlhtcec2.config.ConvertStatusUtil;
import com.rc.saas.mini.hlhtcec2.config.FailReasonConsts;
import com.rc.saas.mini.mapper.rc.RcMemberFlagMapper;
import com.rc.saas.mini.model.elec.*;
import com.rc.saas.mini.model.enterprise.EnterpriseMember;
import com.rc.saas.mini.model.enterprise.EnterpriseSubmember;
import com.rc.saas.mini.model.enterprise.EnterpriseSubmemberShare;
import com.rc.saas.mini.model.enterprise.EnterpriseSubmemberShareExample;
import com.rc.saas.mini.model.hlhtsk.HlhtskTenant;
import com.rc.saas.mini.model.member.MemberAccount;
import com.rc.saas.mini.model.member.MemberInfo;
import com.rc.saas.mini.model.order.OrderInfo;
import com.rc.saas.mini.model.order.OrderInfoExample;
import com.rc.saas.mini.model.rc.RcMemberFlag;
import com.rc.saas.mini.model.tenant.Tenant;
import com.rc.saas.mini.model.tenant.TenantSetting;
import com.rc.saas.mini.search.ElecStationPriceSearch;
import com.rc.saas.mini.service.elec.*;
import com.rc.saas.mini.service.enterprise.EnterpriseMemberService;
import com.rc.saas.mini.service.enterprise.EnterpriseSubmemberShareService;
import com.rc.saas.mini.service.hlhtsk.HlhtskTenantService;
import com.rc.saas.mini.service.member.MemberAccountService;
import com.rc.saas.mini.service.order.OrderInfoService;
import com.rc.saas.mini.service.tenant.TenantService;
import com.rc.saas.mini.service.tenant.TenantSettingService;
import com.rc.saas.mini.utils.AESEncrypter;
import com.rc.saas.mini.utils.PubFetchTool;
import com.rc.saas.mini.utils.StationOutUtil;
import com.rc.saas.mini.vo.cec.StdRequest;
import com.rc.saas.mini.vo.charge.CommandCurrDataReq;
import com.rc.saas.mini.vo.charge.CommandStartReq;
import com.rc.saas.mini.vo.charge.CommandStopReq;
import com.rc.saas.mini.vo.charge.QueryGunDetailVo;
import com.rc.saas.mini.vo.elec.ElecStationExtInfo;
import com.rc.saas.mini.vo.elec.ElecStationOutVo;
import com.rc.saas.mini.vo.hlhtcec2.StartChargeResult;
import com.rc.saas.mini.vo.hlhtcec2.StopChargeResult;
import com.rc.saas.mini.vo.hlhtcec2.WxEquipChargeStatusResult;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author wangzhengwei
 * @create 2021/12/21
 */
@Service
public class ChargeServiceImpl implements ChargeService {
    private static Logger logger = LogManager.getLogger(ChargeServiceImpl.class);

    //B611 电压,B621 电流;C904 SOC,C88D 充电电量,C88E 消费金额,D99E 基本电费,ELEC
    private final String ELEC_B611 = "B611";
    private final String ELEC_B621 = "B621";
    private final String ELEC_C904 = "C904";
    private final String ELEC_C840 = "C840";
    private final String ELEC_C88D = "C88D";
    private final String ELEC_C88E = "C88E";
    private final String ELEC_D88E = "D88E";
    private final String ELEC_E98E = "E98E";
    //private final String ELEC_D99E = "D99E";

    @Autowired
    private UpYunConfig upYunConfig;

    @Autowired
    private EnterpriseSubmemberShareService submemberShareService;

    @Autowired
    private MemberAccountService memberAccountService;

    @Autowired
    private TenantSettingService tenantSettingService;

    @Autowired
    private OrderInfoService orderInfoService;

    @Autowired
    private ElecStationService elecStationService;

    @Autowired
    private HlhtskTenantService hlhtskTenantService;

    @Autowired
    private ElecPileService elecPileService;

    @Autowired
    private ChargerClientRouter chargerClientRouter;

    @Autowired
    private ElecGunService elecGunService;

    @Autowired
    private CurrDataFacade currDataFacade;

    @Autowired
    private UidGenerator uidGenerator;

    @Autowired
    private ElecStationAssemble elecStationAssemble;

    @Autowired
    private ElecStationOutService elecStationOutService;

    @Autowired
    private EnterpriseSubmemberShareService enterpriseSubmemberShareService;

    @Autowired
    private TenantService tenantService;

    @Autowired
    private EnterpriseMemberService enterpriseMemberService;

    @Autowired
    private EnterpriseSubmemberService enterpriseSubmemberService;

    @Autowired
    private ElecStationPriceService elecStationPriceService;
    @Autowired
    private RedisLoader redisLoader;
    @Autowired
    private RcMemberFlagMapper rcMemberFlagMapper;

    @Override
    public TResponse query_gun_detail(MemberInfo memberInfo, ElecStation elecStation, ElecGun elecGun,
                                      String hlhtTenantCode, String hlhtOperatorId, String gunNo, String qrCode) {
        String tenantCode = memberInfo.getTenantCode();

        //显示最佳优惠优惠
        ElecStationExtInfo elecStationFindVo = elecStationAssemble.selectElecStationDetail(memberInfo, elecStation.getElecStationId());
        //格式化
        if (elecStationFindVo.getBestDiscount() != null) {
            elecStationFindVo.getBestDiscount().setBeginTime(elecStationFindVo.getBestDiscount().getBeginTime());
            elecStationFindVo.getBestDiscount().setEndTime(elecStationFindVo.getBestDiscount().getEndTime());
        }
        if (elecStationFindVo.getEnterpriseBestDiscount() != null) {
            elecStationFindVo.getEnterpriseBestDiscount().setBeginTime(elecStationFindVo.getBestDiscount().getBeginTime());
            elecStationFindVo.getEnterpriseBestDiscount().setEndTime(elecStationFindVo.getBestDiscount().getEndTime());
        }

        ////是否有优惠劵 todo
        //List<MemberTicket> memberTickets = memberTicketService.selectByElecStationId(memberInfo.getMemberId(), elecStation.getElecStationId(), tenantCode);

        //int isTicket = memberTickets.size() > 0 ? 1 : 0;

        //出场信息
        ElecStationOutVo elecStationOutVo = assembleStationOutData(elecStation, null, elecGun, upYunConfig);

        //判断是否是企业会员
        int memberType = WebConstant.CON1.equals(memberInfo.getMemberType()) || WebConstant.CON2.equals(memberInfo.getMemberType()) ? 1 : 0;

        int isShareAmount = 0;
        MemberAccount memberAccount = memberAccountService.selectByPrimaryKey(memberInfo.getMemberId());
        //member_account
        //enterprise_submember_share
        //如果该用户是企业会员 并且设置了共享余额(指定日期内) + 企业余额不足 才显示共享余额充电
        boolean flagEnt = false;
        if ("2".equals(memberInfo.getMemberType())) {
            flagEnt = true;
        }
        if (flagEnt && memberAccount.getEnterpriseAccount().intValue() < 2) {
            EnterpriseSubmemberShareExample example = new EnterpriseSubmemberShareExample();
            example.createCriteria().andMemberIdEqualTo(memberInfo.getMemberId()).andStatusEqualTo(WebConstant.CON1)
                    .andBeginTimeLessThanOrEqualTo(new Date()).andEndTimeGreaterThanOrEqualTo(new Date());
            EnterpriseSubmemberShare shareAmount = enterpriseSubmemberShareService.selectByExample(example).stream().findFirst().orElseGet(() -> null);
            if (shareAmount != null) {
                isShareAmount = 1;
            }
        }
        Map result = new HashMap();
        QueryGunDetailVo queryGunDetailVo = new QueryGunDetailVo();
        //充电跳转图案地址
        Tenant tenant = tenantService.selectByTenantCode(tenantCode);
        String tenantImg = upYunConfig.getDownloadRoot() + tenant.getTenantLogoImg();
        EnterpriseMember enterpriseMember = null;
        if (memberType == 1) {
            enterpriseMember = enterpriseMemberService.selectByPrimaryKey(memberInfo.getEnterpriseMemberId());
        }
        if (!memberInfo.getTenantCode().equals(elecStation.getTenantCode())) {
            elecStationFindVo.setHlhtTenantCode(elecStation.getTenantCode());
        }
        result.put("elecGun", elecGun);
        result.put("elecStationFindVo", elecStationFindVo);
        result.put("tenantImg", tenantImg);
        queryGunDetailVo.setElecGun(elecGun);
        queryGunDetailVo.setElecStationFindVo(elecStationFindVo);
        queryGunDetailVo.setTenantImg(tenantImg);
        if (elecStationOutVo != null) {
            //是否需要车牌 （0否 1是)
            result.put("isNeedNumber", "1".equals(elecStationOutVo.getIsNeedNumber()) ? "0" : "1");
        } else {
            result.put("isNeedNumber", "1");
        }
        queryGunDetailVo.setIsLimitSoc(result.get("isNeedNumber").toString());
        //memberType(用户类型)0个人 1企业主帐户 2企业子帐户 3互联互通用户
        result.put("memberType", memberInfo.getMemberType());
        queryGunDetailVo.setMemberType(memberInfo.getMemberType());
        //isShareAmount （是否有共享充电）0否，1是
        result.put("isShareAmount", isShareAmount);
        queryGunDetailVo.setIsShareAmount(String.valueOf(isShareAmount));
        //0 否，1是 有优惠劵
        //result.put("isTicket", isTicket);
        //result.put("isTicket", isTicket);
        //是否显示优惠劵
        result.put("isShowTicket", 1);
        queryGunDetailVo.setIsShareAmount("1");
        //桩群出场的hit
        result.put("elecStationOutHit", elecStationOutVo.getHint());
        queryGunDetailVo.setElecStationOutHit(elecStationOutVo.getHint());
        //0 否，1是开启soc
        result.put("isLimitSoc", 0);
        queryGunDetailVo.setIsLimitSoc("0");
        if (memberInfo.getLimitSoc() == null) {
            memberInfo.setLimitSoc(PlatformConstant.DEFAULT_CHARGE_MAX_SOC);
        }
        //是否是有效子会员 1 有效子会员 0 非有效子会员
        EnterpriseSubmember enterpriseSubmember = enterpriseSubmemberService.selectByPrimaryKey(memberInfo.getMemberId());
        if ("2".equals(memberInfo.getMemberType()) && "0".equals(enterpriseSubmember.getStatus())) {
            result.put("usableSubmember", 1);
        } else {
            result.put("usableSubmember", 0);
        }
        queryGunDetailVo.setUsableSubmember(result.get("usableSubmember").toString());
        ElecStationPriceSearch elecStationPriceSearch = new ElecStationPriceSearch();
        elecStationPriceSearch.setElecStationId(elecStation.getElecStationId());
        //elecStationPriceSearch.setTenantCode(tenantCode);
        ElecStationPrice elecStationPrice = elecStationPriceService.getCurrentPrice(elecStationPriceSearch);
        result.put("elecStationPrice", elecStationPrice);
        queryGunDetailVo.setElecStationPrice(elecStationPrice);
        result.put("limitSoc", memberInfo.getLimitSoc());
        queryGunDetailVo.setLimitSoc(memberInfo.getLimitSoc().toString());
        return TResponse.SUCCESS_DATA(queryGunDetailVo);
    }


    @Override
    public TResponse checkStartMemberAccount(MemberInfo memberInfo, MemberAccount memberAccount, String hlhtTenantCode, String hlhtOperatorId, String accountType) {
        //平台参数设置
        TenantSetting tenantSetting = tenantSettingService.selectByPrimaryKey(memberInfo.getTenantCode());

        //判断是个人钱包还是企业钱包:支付的账户类型 0个人钱包 1企业钱包(不存在共享余额)
        BigDecimal money = null;
        if ("2".equals(accountType)) {//共享余额
            EnterpriseSubmemberShare share = submemberShareService.selectSubmeberByMemberId(memberAccount.getMemberId());
            if (memberInfo.getEnterpriseMemberId() != null) {
                MemberAccount masterAccount = memberAccountService.selectByPrimaryKey(memberInfo.getEnterpriseMemberId());
                if (masterAccount != null) {
                    if (tenantSetting != null && tenantSetting.getStartShareChargeAccountMin() != null) {
                        if (masterAccount.getEnterpriseAccount().compareTo(tenantSetting.getStartChargeAccountMin()) < 0) {
                            return TResponse.FAIL("当前用户的主会员企业钱包不足,请选择其他支付类型！！");
                        }
                    } else if (masterAccount.getEnterpriseAccount().compareTo(BigDecimal.ZERO) < 1) {
                        return TResponse.FAIL("当前用户的主会员企业钱包不足,请选择其他支付类型！！");
                    }
                } else {
                    return TResponse.FAIL("当前用户的主会员余额不足,请选择其他支付类型！！");
                }
            } else {
                return TResponse.FAIL("当前用户的主会员不存在,请选择其他支付类型！！");
            }

            if (share != null) {
                //子会员每日限定充电量-已使用的充电量
                if (share.getFixedAccount().subtract(share.getSharePower()).compareTo(BigDecimal.ONE) < 0) {
                    return TResponse.FAIL("当前设置的共享余额的电量值不足1度,请选择其他支付类型！！");
                }
                //子会员每日限定金额-已使用的金额
                if (share.getFixedAccount().subtract(share.getShareAccount()).compareTo(BigDecimal.ONE) < 0) {
                    return TResponse.FAIL("当前设置的共享余额的金额不足1元,请选择其他支付类型！！");
                }
                money = share.getFixedAccount().subtract(share.getShareAccount());
            } else {
                return TResponse.FAIL("当前没有设置共享余额,请选择其他支付类型！！");
            }
            return TResponse.SUCCESS();
        }

        if ("1".equals(accountType)) {
            RcMemberFlag rcMemberFlag = rcMemberFlagMapper.selectByPrimaryKey(memberInfo.getMemberId());
            EnterpriseMember enterpriseMember = enterpriseMemberService.selectByPrimaryKey(rcMemberFlag.getEnterpriseId());
            //企业余额加授信剩余额度
            money = enterpriseMember.getEnterpriseAccount().add(enterpriseMember.getRemainCreditAmount());
        } else if ("0".equals(accountType)) {
            money = memberAccount.getAccount();
        } else {
            //共享钱包
            money = memberAccount.getPaymentRefundAccount();
        }

        // 单充会员判断是否使用中,多充会员忽略;
        //充电类型(elec_type) 0单冲  1多充 默认0
        //用户是否在充电(elec_status) 0不是，1正充电 默认0
        if ("0".equals(memberInfo.getChargeType()) && "1".equals(memberInfo.getChargeStatus())) {
            return TResponse.FAIL("单充会员正在使用中");
        } else if ("1".equals(memberInfo.getChargeType())) {
            OrderInfoExample orderInfoExample = new OrderInfoExample();
            orderInfoExample.createCriteria().andMemberIdEqualTo(memberInfo.getMemberId()).andStatusEqualTo("1");
            Long count = orderInfoService.countByExample(orderInfoExample) + 1;
            if (count > 1) {
                BigDecimal startMoney = tenantSetting.getStartChargeAccountMin().multiply(BigDecimal.valueOf(count));
                //多充会员启动的余额大于  单次启动金额*（正在充电订单数+1）
                if (startMoney.compareTo(money) > 0) {
                    return TResponse.FAIL("余额不足（一号多充用户" + tenantSetting.getStartMultChargeAccountMin() + "元/车）");
                }
            }
        }

        BigDecimal start_charge_account_limit = tenantSettingService.query_start_charge_account_limit(memberInfo.getTenantCode());
        if (money == null || money.compareTo(start_charge_account_limit) == -1) {
            TResponse tResponse = TResponse.FAIL();
            tResponse.setStatus(400);
            //tResponse.setMessage("余额少于" + start_charge_account_limit + "元");
            tResponse.setMessage("钱包余额不足");
            return tResponse;
        }

        return TResponse.SUCCESS();
    }

    @Override
    public StartChargeResult assembleStartChargeResult(CommandStartReq commandStartReq) {
        String tenantCode = commandStartReq.getTenantCode();

        //生成预充电订单号
        String outOrderNum = uidGenerator.genChargeOutOrderNum(commandStartReq.getGunNo());

        commandStartReq.setOutOrderNum(outOrderNum);
        final StartChargeResult startChargeResult = new StartChargeResult();
        startChargeResult.setStartChargeSeq(outOrderNum);
        startChargeResult.setConnectorID(commandStartReq.getGunNo());

        //默认成功
        startChargeResult.setSuccStat(0);
        startChargeResult.setFailReason(0);

        //查询桩群中的服务器域名
        ElecStation elecStation = elecStationService.selectByPrimaryKey(commandStartReq.getElecStationId());
        try {
            //加密
            ObjectMapper objectMapper = new ObjectMapper();
            String respData = objectMapper.writeValueAsString(commandStartReq);
            String jsonData = encryptData(respData, tenantCode);
            StdRequest tRequest = genSuccessReq(jsonData, tenantCode);

            logger.info(tenantCode + "发送充电指令,:{},:{}", outOrderNum, commandStartReq.getGunNo());
            //  判断桩是否存在Domain  ElecServerSpliter
            ElecPile elecPile = elecPileService.selectPileByPileId(commandStartReq.getElecPileId());
            TResponse tResponse;
            if (StringUtils.isNotBlank(elecPile.getElecServerDomain())) {
                tResponse = chargerClientRouter.query_start_charge(elecPile.getElecServerDomain(), elecPile.getElecServerSpliter(), tRequest, commandStartReq);
            } else {
                tResponse = chargerClientRouter.query_start_charge(elecStation.getElecServerDomain(), elecStation.getElecServerSpliter(), tRequest, commandStartReq);
            }

            //指令返回成功,但桩可能还没真正启动
            if (tResponse.getStatus() == HttpConstant.STATUS_SUCCESS) {
                //第一次查找订单
                OrderInfo orderInfo = orderInfoService.selectOrderByOutOrderNum(outOrderNum, tenantCode);
                //订单状态(0:未充电,1:充电中,2:已结束充电 3:充电结算中) 默认0
                if (orderInfo != null && "1".equals(orderInfo.getStatus())) {
                    logger.info(tenantCode + "充电启动成功:{},:{}", outOrderNum, commandStartReq.getGunNo());

                    startChargeResult.setStartChargeSeqStat(2); //充电中
                } else {
                    //如果成功StartChargeSeqStat需回复1（启动中）
                    //启动中
                    startChargeResult.setStartChargeSeqStat(1);
                }
            } else {
                logger.info(tenantCode + "充电启动失败:{},:{}", outOrderNum, tResponse.getMessage());

                startChargeResult.setStartChargeSeqStat(5); //未知
                //失败原因
                startChargeResult.setSuccStat(1);
                if (tResponse.getStatus() == HttpConstant.STATUS_FAIL) {
                    startChargeResult.setFailReason(FailReasonConsts.EXT_FAIL_REASON17);
                } else if (tResponse.getStatus() == HttpConstant.FAIL_CODE_501) {
                    startChargeResult.setFailReason(FailReasonConsts.EXT_FAIL_REASON3);
                    //自定义失败原因:余额不足或其它(这个错误码只有瑞晨有)
                } else if (tResponse.getStatus() == HttpConstant.FAIL_CODE_502) {
                    startChargeResult.setFailReason(FailReasonConsts.EXT_FAIL_REASON44);
                    //自定义失败原因:有未支付的充电订单,不允许开启充电(上次订单还没结算完，请稍等)
                } else {
                    startChargeResult.setFailReason(FailReasonConsts.EXT_FAIL_REASON17);
                    //自定义失败原因:开始充电异常
                }
                startChargeResult.setFailReasonString(tResponse.getMessage());
            }

            return startChargeResult;
        } catch (Exception e) {
            startChargeResult.setSuccStat(1);
            startChargeResult.setFailReasonString("发送启动充电指令失败");
            logger.error("发送启动充电指令失败", e);
            return startChargeResult;
        }
    }

    @Override
    public WxEquipChargeStatusResult assembleEquipChargeStatusResult(CommandStartReq commandStartReq) {
        String tenantCode = commandStartReq.getTenantCode();
        //外部订单号
        final String outOrderNum = commandStartReq.getOutOrderNum();

        WxEquipChargeStatusResult equipChargeStatusResult = new WxEquipChargeStatusResult();
        equipChargeStatusResult.setStartChargeSeq(outOrderNum);

        //从order_info表查找订单
        OrderInfo orderInfo = orderInfoService.selectOrderByOutOrderNum(outOrderNum, tenantCode);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        if (orderInfo != null) {
            ElecGun elecGun = elecGunService.selectByPrimaryKey(orderInfo.getElecGunId());
            equipChargeStatusResult.setConnectorID(elecGun.getGunNo());

            //充电订单状态
            Integer startChargesSeqStat = ConvertStatusUtil.convertEquipChargeStatus(orderInfo.getStatus());
            equipChargeStatusResult.setStartChargeSeqStat(startChargesSeqStat);

            // 如果中途停止充电，如拔枪/急停，就推送异步通知
            //由CallbackStopChargeListener负责监听

            //充电设备接口状态
            //Integer connectorStatus = CommonUtil.convertConnectorStatus(order.getStatus());
            //equipChargeStatusResult.setConnectorStatus(connectorStatus);

            //订单状态:String status;//订单状态(0:未充电,1:充电中,2:完成)(从redis中取)
            if (orderInfo.getStatus().equals("1")) {
                CommandCurrDataReq commandCurrDataReq = new CommandCurrDataReq();
                commandCurrDataReq.setTenantCode(orderInfo.getTenantCode());
                commandCurrDataReq.setMemberId(orderInfo.getMemberId());
                commandCurrDataReq.setElecPileId(orderInfo.getElecPileId());
                commandCurrDataReq.setGunNum(elecGun.getGunNum());

                //B611 电压,B621 电流;C904 SOC,C88D 充电电量,C88E 消费金额,D99E 基本电费,ELEC
                commandCurrDataReq.setCode(new String[]{ELEC_B611, ELEC_B621, ELEC_C904, ELEC_C88D, ELEC_C88E, ELEC_C840, ELEC_D88E, ELEC_E98E});

                logger.info(tenantCode + ":本次采样入参:{}", commandCurrDataReq.toString());

                //查询桩群中的服务器域名
                ElecStation elecStation = elecStationService.selectByPrimaryKey(orderInfo.getElecStationId());

                try {
                    //加密
                    ObjectMapper objectMapper = new ObjectMapper();
                    String respData = objectMapper.writeValueAsString(commandCurrDataReq);
                    String jsonData = encryptData(respData, tenantCode);
                    StdRequest tRequest = genSuccessReq(jsonData, tenantCode);

                    TResponse tResponse = currDataFacade.getCurrDataMap(commandCurrDataReq);

                    if (tResponse.getStatus() == HttpConstant.STATUS_SUCCESS) {
                        Map<String, Object> result = (Map<String, Object>) tResponse.getData();
                        logger.info(tenantCode + ":本次采样原值:{}:{}", orderInfo.getOrderNum(), result);


                        //获取SOC
                        if (result.containsKey(ELEC_C904)) {
                            equipChargeStatusResult.setSoc(result.get(ELEC_C904) == null ? BigDecimal.ZERO
                                    : new BigDecimal(String.valueOf(result.get(ELEC_C904))).setScale(2, BigDecimal.ROUND_HALF_UP));
                        }

                        //所充电量
                        if (result.containsKey(ELEC_C88D)) {
                            equipChargeStatusResult.setTotalPower(result.get(ELEC_C88D) == null ? BigDecimal.ZERO
                                    : new BigDecimal(String.valueOf(result.get(ELEC_C88D))).setScale(3, BigDecimal.ROUND_HALF_UP));
                        }

                        //a相电压
                        if (result.containsKey(ELEC_B611)) {
                            equipChargeStatusResult.setVoltageA(result.get(ELEC_B611) == null ? new BigDecimal("0")
                                    : new BigDecimal(String.valueOf(result.get(ELEC_B611))).setScale(2, BigDecimal.ROUND_HALF_UP));
                        }

                        //a相电流
                        if (result.containsKey(ELEC_B621)) {
                            equipChargeStatusResult.setCurrentA(result.get(ELEC_B621) == null ? new BigDecimal("0")
                                    : new BigDecimal(String.valueOf(result.get(ELEC_B621))).setScale(2, BigDecimal.ROUND_HALF_UP));
                        }

                        //电枪状态码
                        if (result.containsKey(ELEC_C840)) {
                            Integer connectorStatus = ConvertStatusUtil.convertEquipChargeConnectorStatus(String.valueOf(result.get(ELEC_C840)));
                            equipChargeStatusResult.setConnectorStatus(connectorStatus);
                        }

                        //消费金额
                        if (result.containsKey(ELEC_C88E)) {
                            equipChargeStatusResult.setTotalMoney(result.get(ELEC_C88E) == null ? new BigDecimal("0")
                                    : new BigDecimal(String.valueOf(result.get(ELEC_C88E))).setScale(2, BigDecimal.ROUND_HALF_UP));
                        }

                        //基本电费
                        if (result.containsKey(ELEC_D88E)) {
                            equipChargeStatusResult.setElecMoney(result.get(ELEC_D88E) == null ? new BigDecimal("0")
                                    : new BigDecimal(String.valueOf(result.get(ELEC_D88E))).setScale(2, BigDecimal.ROUND_HALF_UP));
                        }
                        //服务费
                        if (result.containsKey(ELEC_E98E)) {
                            equipChargeStatusResult.setSeviceMoney(result.get(ELEC_E98E) == null ? new BigDecimal("0")
                                    : new BigDecimal(String.valueOf(result.get(ELEC_E98E))).setScale(2, BigDecimal.ROUND_HALF_UP));
                        }

                        //订单的开始充电时间
                        equipChargeStatusResult.setStartTime(sdf.format(orderInfo.getStartTime()));

                        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
                        format.setTimeZone(TimeZone.getTimeZone("GMT+0"));
                        Date date = new Date(System.currentTimeMillis() - orderInfo.getStartTime().getTime());
                        equipChargeStatusResult.setDuration(format.format(date));

                        equipChargeStatusResult.setCarNum(orderInfo.getCarNum());
                        logger.info(tenantCode + ":" + equipChargeStatusResult.getCarNum() + ":充电时长计算:{}", equipChargeStatusResult.getDuration());
                        equipChargeStatusResult.setOrderStatus(orderInfo.getStatus());
                        //本次采样时间
                        equipChargeStatusResult.setEndTime(sdf.format(System.currentTimeMillis()));
                    } else {
                        logger.info(tenantCode + ":本次采样异常:{}", outOrderNum);
                    }

                    StringBuilder sb = new StringBuilder();
                    sb.append(sdf.format(System.currentTimeMillis()));
                    sb.append(" SOC:");
                    sb.append(equipChargeStatusResult.getSoc());

                    sb.append(" POWER:");
                    sb.append(equipChargeStatusResult.getTotalPower());

                    sb.append(" V:");
                    sb.append(equipChargeStatusResult.getVoltageA());

                    sb.append(" C:");
                    sb.append(equipChargeStatusResult.getCurrentA());

                    sb.append(" GUNSTATUS:");
                    sb.append(equipChargeStatusResult.getConnectorStatus());

                    logger.info(tenantCode + ":本次采样:{}", outOrderNum + ":" + sb.toString());
                } catch (Exception e) {
                    logger.error(tenantCode + ":发送读取redis命令失败", e);
                }
                equipChargeStatusResult.setSurplusTime(getRemainChargingTime(orderInfo.getOrderNum()));
                equipChargeStatusResult.setTemperatureHigh(getTemperatureHigh(orderInfo.getOrderNum()));


            } else if (orderInfo.getStatus().equals("2")) {//已完成充电(从数据库取)
                //CEC标准
                //1: 空闲；
                //2: 占用（未充电）；
                //3: 占用（充电中）；
                //4: 占用（预约锁定）；
                //255: 故障
                equipChargeStatusResult.setConnectorStatus(1);
                equipChargeStatusResult.setOrderStatus(orderInfo.getStatus());
                //目前没有收集电流和电压参数
                equipChargeStatusResult.setCurrentA(new BigDecimal("0"));
                equipChargeStatusResult.setVoltageA(new BigDecimal("0"));
                equipChargeStatusResult.setSurplusTime(equipChargeStatusResult.getDuration());
                equipChargeStatusResult.setTemperatureHigh(getTemperatureHigh(orderInfo.getOrderNum()));
            }
        }

        if (orderInfo != null) {
            equipChargeStatusResult.setOrderId(orderInfo.getOrderId());
        }
        if (equipChargeStatusResult.getSoc() == null) {
            equipChargeStatusResult.setSoc(BigDecimal.ZERO);
        }
        return equipChargeStatusResult;
    }

    @Override
    public StopChargeResult assembleStopChargeResult(CommandStopReq commandStopReq) {
        String tenantCode = commandStopReq.getTenantCode();
        //外部订单号
        final String outOrderNum = commandStopReq.getOutOrderNum();

        StopChargeResult stopChargeResult = new StopChargeResult();
        stopChargeResult.setStartChargeSeq(outOrderNum);
        //默认成功
        stopChargeResult.setSuccStat(0);
        stopChargeResult.setFailReason(0);

        //第一次查找订单信息,从order_info表查找订单
        OrderInfo orderInfo = orderInfoService.selectOrderByOutOrderNum(outOrderNum, tenantCode);
        if (orderInfo == null) {
            stopChargeResult.setSuccStat(1);
            stopChargeResult.setFailReason(FailReasonConsts.EXT_FAIL_REASON30);//自定义失败原因30:该订单号不存在
            stopChargeResult.setStartChargeSeqStat(5);
            logger.warn(tenantCode + ":30,该订单号不存在:{}", outOrderNum);

            return stopChargeResult;
        }

        //订单已经结束充电
        //订单状态:String status;//订单状态(0:未充电,1:充电中,2:完成)(从redis中取)
        if (orderInfo.getStatus().equals("2")) {
            stopChargeResult.setSuccStat(1);
            stopChargeResult.setFailReason(FailReasonConsts.EXT_FAIL_REASON16);//自定义失败原因16	已经结束充电，不能重复结束充电
            stopChargeResult.setStartChargeSeqStat(5);
            logger.warn(tenantCode + ":16,订单已经结束充电，不能重复结束充电:{}", outOrderNum);

            return stopChargeResult;
        }

        //枪信息
        ElecGun elecGun = elecGunService.selectByPrimaryKey(orderInfo.getElecGunId());
        if (elecGun == null) {
            stopChargeResult.setSuccStat(1);
            stopChargeResult.setFailReason(1);
            stopChargeResult.setStartChargeSeqStat(5);
            logger.warn(tenantCode + ":找不到对应的枪:{}", commandStopReq.getGunNo());

            return stopChargeResult;
        }

        //桩信息
        ElecPile elecPile = elecPileService.selectByPrimaryKey(commandStopReq.getElecPileId());

        //验证桩是否在线
        if (isOffLine(elecPile)) {
            stopChargeResult.setSuccStat(1);
            stopChargeResult.setFailReason(2);
            stopChargeResult.setStartChargeSeqStat(5);
            logger.warn(commandStopReq.getGunNo() + "电桩已离线");

            return stopChargeResult;
        }

        //桩群信息
        ElecStation elecStation = elecStationService.selectByPrimaryKey(elecPile.getElecStationId());

        try {
            //status枪使用状态 0：空闲，1：使用中  2:插枪中 默认0
            if (elecGun.getStatus() != null) {
                if (elecGun.getStatus() != 1) {
                    //使用中
                    //如果发送停止命令时，枪的状态不是充电中，并且订单生成时间大于100秒（防止枪状态与平台不同步）。那么直接后台结算订单
                    if ((System.currentTimeMillis() - orderInfo.getStartTime().getTime()) / 1000 > 100) {
                        //发送指令
                        TResponse tResponse = chargerClientRouter.updateOrder(elecStation.getElecServerDomain(), elecStation.getElecServerSpliter(), orderInfo.getOrderId());
                        if (tResponse.getStatus() == HttpConstant.STATUS_SUCCESS) {
                            logger.info(tenantCode + ":发送订单自动结算成功:{}", outOrderNum);

                            //直接返回,不再执行以下的停充指令
                            stopChargeResult.setStartChargeSeqStat(4);//已结束
                            return stopChargeResult;
                        } else {
                            logger.error(tenantCode + ":发送订单自动结算失败:{}", outOrderNum);
                            stopChargeResult.setStartChargeSeqStat(5); //未知

                            //直接返回,不再执行以下的停充指令
                            stopChargeResult.setFailReason(5);//自定义失败原因:上次订单还没结算完，请稍等(这个错误码只有瑞晨有)
                            return stopChargeResult;
                        }
                    }
                }
            }

            //加密
            ObjectMapper objectMapper = new ObjectMapper();
            String respData = objectMapper.writeValueAsString(commandStopReq);
            String jsonData = encryptData(respData, tenantCode);
            StdRequest tRequest = genSuccessReq(jsonData, tenantCode);

            logger.info(tenantCode + ":发送结束指令,:{},:{}", outOrderNum, elecGun.getGunNo());

            ElecPile elecPileVo = elecPileService.selectPileByPileId(elecPile.getElecPileId());
            TResponse tResponse;
            if (StringUtils.isNotBlank(elecPileVo.getElecServerDomain())) {
                tResponse = chargerClientRouter.query_stop_charge(elecPileVo.getElecServerDomain(), elecPileVo.getElecServerSpliter(), tRequest, commandStopReq);
            } else {
                tResponse = chargerClientRouter.query_stop_charge(elecStation.getElecServerDomain(), elecStation.getElecServerSpliter(), tRequest, commandStopReq);
            }
            if (tResponse.getStatus() == HttpConstant.STATUS_SUCCESS) {
                //指定返回成功,但桩可能还没真正结束
                //第一次查找订单
                logger.info(tenantCode + ":结束订单，正在查询结算订单:{}", outOrderNum);
                OrderInfo orderInfo2 = orderInfoService.selectOrderByOutOrderNum(outOrderNum, tenantCode);

                if (orderInfo2 != null && "2".equals(orderInfo2.getStatus())) {
                    logger.info(tenantCode + ":结束订单，返回成功:{}", outOrderNum);
                    //已结束
                    stopChargeResult.setStartChargeSeqStat(4);
                } else {
                    //如果成功StartChargeSeqStat需回复3（停止中）
                    //停止中
                    stopChargeResult.setStartChargeSeqStat(3);
                }
            } else {
                logger.info(tenantCode + "充电结束失败:{},:{}", outOrderNum, tResponse.getMessage());
                //停止中
                stopChargeResult.setStartChargeSeqStat(5);

                //失败原因
                stopChargeResult.setSuccStat(1);
                if (tResponse.getStatus() == HttpConstant.STATUS_FAIL) {
                    //自定义失败原因:结束充电失败
                    stopChargeResult.setFailReason(FailReasonConsts.EXT_FAIL_REASON38);
                } else if (tResponse.getStatus() == HttpConstant.FAIL_CODE_501) {
                    //自定义失败原因:余额不足或其它(这个错误码只有瑞晨有)
                    stopChargeResult.setFailReason(FailReasonConsts.EXT_FAIL_REASON4);
                } else if (tResponse.getStatus() == HttpConstant.FAIL_CODE_502) {
                    //自定义失败原因:上次订单还没结算完，请稍等(这个错误码只有瑞晨有)
                    stopChargeResult.setFailReason(FailReasonConsts.EXT_FAIL_REASON5);
                } else {
                    //自定义失败原因:结束充电失败
                    stopChargeResult.setFailReason(FailReasonConsts.EXT_FAIL_REASON38);
                }
            }
            return stopChargeResult;
        } catch (Exception e) {
            logger.error(tenantCode + ":发送结束指令失败", e);
            stopChargeResult.setSuccStat(1);
            stopChargeResult.setStartChargeSeqStat(1);
            stopChargeResult.setFailReason(38);
            stopChargeResult.setFailReason(FailReasonConsts.EXT_FAIL_REASON38);
            return stopChargeResult;
        }

    }


    /**
     * 通过桩群，订单，和枪编号获取桩群出场信息
     */
    @Override
    public ElecStationOutVo assembleStationOutData(ElecStation elecStation, OrderInfo orderInfo, ElecGun elecGun, UpYunConfig upYunConfig) {
        ElecStationOutVo elecStationOutVo = new ElecStationOutVo();
        ElecStationOut elecStationOut = elecStationOutService.selectElecStationOutByElecStationId(elecStation.getElecStationId());
        if (elecStationOut != null) {
            if (elecStationOut.getOutImage1() != null) {
                elecStationOut.setOutImage1(upYunConfig.getDownloadRoot() + elecStationOut.getOutImage1());
            }
            if (elecStationOut.getOutImage2() != null) {
                elecStationOut.setOutImage2(upYunConfig.getDownloadRoot() + elecStationOut.getOutImage2());
            }
            if (elecStationOut.getOutImage3() != null) {
                elecStationOut.setOutImage3(upYunConfig.getDownloadRoot() + elecStationOut.getOutImage3());
            }
            elecStationOutVo = new ElecStationOutVo(elecStationOut);
        } else {
            //默认
            elecStationOutVo.setPrinterType(WebConstant.CON0);
            elecStationOutVo.setElecStationId(elecStation.getElecStationId());
            elecStationOutVo.setImage1(elecStation.getStationImg1() == null ? "" : (upYunConfig.getDownloadRoot() + elecStation.getStationImg1()));
            elecStationOutVo.setImage2(elecStation.getStationImg2() == null ? "" : (upYunConfig.getDownloadRoot() + elecStation.getStationImg2()));
            elecStationOutVo.setImage3(elecStation.getStationImg3() == null ? "" : (upYunConfig.getDownloadRoot() + elecStation.getStationImg3()));
            elecStationOutVo.setHint(elecStation.getHint());
            elecStationOutVo.setIsFreeParking(elecStation.getIsFreeParking());
        }
        if (orderInfo != null) {
            elecStationOutVo.setOrderNum(orderInfo.getOrderNum());
            elecStationOutVo.setCarNumber(orderInfo.getCarNum());
            elecStationOutVo.setStationName(elecStation.getStationName());
            elecStationOutVo.setIsCharge(orderInfo.getStatus());
            //返回二维码的字符串
            if (orderInfo.getEndTime() != null && elecGun != null) {
                String qrcode = StationOutUtil.generateQrcode(orderInfo, elecStation.getStationName(), elecGun.getGunNo());
                elecStationOutVo.setQrcode(qrcode);
            }
            //万城定制
            if (orderInfo.getHlhtOperatorId() != null && "MA59J8YL8".equals(orderInfo.getHlhtOperatorId())) {
                //万城二维码 qrcode
                elecStationOutVo.setPrinterType(WebConstant.CON2);
                elecStationOutVo.setOutType(elecStationOutVo.getOutType() != null ? elecStationOutVo.getOutType() : "9");
                byte[] wcQrcode = wcQrcode(orderInfo.getHlhtOperatorId(), orderInfo.getOutOrderNum());
                elecStationOutVo.setQrcode(Base64.getEncoder().encodeToString(wcQrcode));
            }
        }
        //logger.info("出场返回的数据:{}", elecStationOutVo.toString());
        return elecStationOutVo;
    }


    @Override
    public String getCurrDataSoc(ElecGun gun, String tenantCode) {
        if (gun == null) {
            return "0";
        }
        CommandCurrDataReq commandCurrDataReq = new CommandCurrDataReq();
        commandCurrDataReq.setTenantCode(gun.getTenantCode());
        commandCurrDataReq.setElecPileId(gun.getElecPileId());
        commandCurrDataReq.setGunNum(gun.getGunNum());
        //B611 电压,B621 电流;C904 SOC,C88D 充电电量,C88E 消费金额,D99E 基本电费,ELEC
        commandCurrDataReq.setCode(new String[]{"C904"});

        //取SOC
        TResponse result = currDataFacade.getCurrDataSoc(commandCurrDataReq);

        if (result.getStatus() == HttpConstant.STATUS_SUCCESS) {
            Map<String, String> map = (Map<String, String>) result.getData();
            return map.get("C904") == null ? "0" : map.get("C904");
        }

        return "0";

        //ObjectMapper objectMapper = new ObjectMapper();
        //CommandCurrDataReq currDataReq = new CommandCurrDataReq();
        //currDataReq.setElecPileId(gun.getElecPileId());
        //currDataReq.setGunNum(gun.getGunNum());
        //currDataReq.setCode(new String[]{"C904"});
        //currDataReq.setTenantCode(tenantCode);
        //String respData = null;
        //try {
        //    respData = objectMapper.writeValueAsString(currDataReq);
        //} catch (JsonProcessingException e) {
        //    logger.error(e);
        //}
        //
        ////查询桩群中的服务器域名
        //ElecStation elecStation = elecStationService.selectByPrimaryKey(gun.getElecStationId());
        ////加密
        //String jsonData = encryptData(respData, tenantCode);
        //StdRequest tRequest = genSuccessReq(jsonData, tenantCode);
        //try {
        //
        //    ElecPile elecPile = elecPileService.selectByPrimaryKey(gun.getElecPileId());
        //    TResponse tResponse;
        //    if (elecPile != null && elecPile.getElecServerDomain() != null) {
        //        tResponse = chargerClientRouter.getCurrDataSoc(elecPile.getElecServerDomain(), elecPile.getElecServerSpliter(), tRequest);
        //    } else {
        //        tResponse = chargerClientRouter.getCurrDataSoc(elecStation.getElecServerDomain(), elecStation.getElecServerSpliter(), tRequest);
        //    }
        //
        //    if (200 == tResponse.getStatus() && tResponse.getData() == null) {
        //        return "0";
        //    }
        //    Map<String, Object> map = (Map<String, Object>) tResponse.getData();
        //    map.put("s", map.get("C904"));
        //    tResponse.put(map);
    }

    /**
     * 验证桩是否在线
     */
    private boolean isOffLine(ElecPile elecPile) {
        //桩status登录状态: 0离线 1在线 默认0
        if (elecPile.getStatus().equals("0")) {
            return true;
        }
        return false;
    }

    /**
     * 封装KyConfig、数据、加密
     */
    protected String encryptData(String respData, String tenantCode) {
        HlhtskTenant hlhtskTenant = hlhtskTenantService.selectByTenantCode(tenantCode);
        String data = PubFetchTool.genDDEncodeData(hlhtskTenant, respData);
        return data;
    }

    /**
     * 封装请求信息
     */
    protected StdRequest genSuccessReq(String data, String tenantCode) {
        StdRequest resp = new StdRequest();
        resp.setData(data);
        resp.setSeq(tenantCode);
        return resp;
    }

    /**
     * 生成二维码信息
     *
     * @param hlhtOperatorId
     * @param startChargeSeq
     * @return
     */
    private byte[] wcQrcode(String hlhtOperatorId, String startChargeSeq) {
        logger.info("controller.query_qrcode_print request:{},:{}", hlhtOperatorId, startChargeSeq);

        StringBuilder sbd = new StringBuilder();

        OrderInfo orderInfo = orderInfoService.selectOrderByOutOrderNum(startChargeSeq);

        ElecStation elecStation = elecStationService.selectByPrimaryKey(orderInfo.getElecStationId());

        sbd.append(orderInfo.getOutOrderNum()).append(",");
        sbd.append(orderInfo.getCarNum()).append(",");
        sbd.append(DateHelper.dataToString(orderInfo.getStartTime(), "yyyy-MM-dd HH:mm:ss")).append(",");
        if (orderInfo.getEndTime() != null) {
            sbd.append(DateHelper.dataToString(orderInfo.getEndTime(), "yyyy-MM-dd HH:mm:ss")).append(",");
        } else {
            sbd.append(DateHelper.dataToString(new Date(), "yyyy-MM-dd HH:mm:ss")).append(",");
        }
        if (elecStation != null) {
            sbd.append(elecStation.getStationName()).append(",");
        }
        sbd.append(DateHelper.dataToString(new Date(), "yyyy-MM-dd HH:mm:ss")).append(",");
        sbd.append(120).append(",");
        sbd.append("185905");

        logger.info("加密前:{}", sbd.toString());
        byte[] bb = new byte[0];
        try {
            bb = AESEncrypter.encrypt(sbd.toString());
            logger.info("加密后:{}", bb);
            return bb;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public String getRemainChargingTime(String orderNum) {

        try {
            OrderInfo orderInfo = orderInfoService.selectOrderByOrderNum(orderNum);
            ElecPile pile = elecPileService.selectByPrimaryKey(orderInfo.getElecPileId());
            ElecGun elecGun = elecGunService.selectByPrimaryKey(orderInfo.getElecGunId());
            String chargeReportTimeKey = DataUtil.getCurrDataKey(pile.getPileRtua(), elecGun.getGunNum(), "8E F1", orderNum);
            String data = redisLoader.getRedis(chargeReportTimeKey);

            if (data != null) {
                return minConvertHourMinSecond(Integer.valueOf(data));
            } else {
                return "00:00:00";
            }

        } catch (Exception e) {
            logger.error(e.getMessage());

            return "00:00:00";
        }

    }


    /**
     * 当前最高单体温度
     *
     * @return
     */
    @Override
    public String getTemperatureHigh(String orderNum) {

        try {
            OrderInfo orderInfo = orderInfoService.selectOrderByOrderNum(orderNum);
            ElecPile pile = elecPileService.selectByPrimaryKey(orderInfo.getElecPileId());
            ElecGun elecGun = elecGunService.selectByPrimaryKey(orderInfo.getElecGunId());
            String stopReasonKey = DataUtil.getCurrDataKey(pile.getPileRtua(), elecGun.getGunNum(), "1F T1", orderNum);
            String data = redisLoader.getRedis(stopReasonKey);
            if (data == null) {
                return "0";
            }
            return data;
        } catch (Exception e) {
            logger.error(e.getMessage());
            return "0";
        }
    }

    public static String minConvertHourMinSecond(Integer min) {
        String result = "";
        if (min != null) {
            Integer m = min;
            String format;
            Object[] array;
            Integer days = m / (60 * 24);
            Integer hours = m / (60) - days * 24;
            Integer minutes;
            Integer second;
            if (days > 0) {
                hours += days * 24;
                minutes = m - hours * 60;
                second = (m - minutes - hours * 60) / 60;
            } else {
                minutes = m - hours * 60 - days * 24 * 60;
                second = (m - minutes - hours * 60) / 60;
            }
            String hoursstr = null;
            String minutesstr = null;
            String secondstr = null;
            if (hours < 10) {
                hoursstr = "0" + hours;
            } else {
                hoursstr = hours + "";
            }
            if (minutes < 10) {
                minutesstr = "0" + minutes;
            } else {
                minutesstr = minutes + "";
            }
            if (second < 10) {
                secondstr = "0" + second;
            } else {
                secondstr = second + "";
            }
            format = "%1$s:%2$s:%3$s";
            array = new Object[]{hoursstr, minutesstr, secondstr};
            result = String.format(format, array);
        }
        return result;
    }


    public static String second2Time(Long second) {
        if (second == null || second < 0) {
            return "00:00";
        }

        long h = second / 3600;
        long m = (second % 3600) / 60;
        long s = second % 60;
        String str = "";
        if (h > 0) {
            str = (h < 10 ? ("0" + h) : h) + ":";
        }
        str += (m < 10 ? ("0" + m) : m) + ":";
        str += (s < 10 ? ("0" + s) : s);
        return str;

    }
}
